<template>
    <Teleport to="body">
        <Transition :name="transitionName">
            <div class="pe-popup" v-show="show" ref="popupRef" v-click-outside="clickOutside"
                :style="{ inset: `${insetTop} ${insetRight} ${insetBottom} ${insetLeft}`, zIndex }">
                <slot></slot>
                <span class="pe-popup-triangle"
                    :style="{ inset: `${triangleTop} ${triangleRight} ${triangleBottom} ${triangleLeft}`, transform: rotate }"></span>
            </div>
        </Transition>
    </Teleport>
</template>

<script setup lang="ts">
import { inject, nextTick, onMounted, ref, watch } from "vue"
import { getInset } from "../../utils/popupUtil";

const show = defineModel<boolean>({ default: false })

/**
 * @param domFlag 外部是否是组件类型
 * @param transitionName 进入离开动画名称
 */
interface Props {
    domFlag?: boolean,
    transitionName?: string
}

const props = withDefaults(defineProps<Props>(), {
    domFlag: true,
    transitionName: "popup"
})
// 弹出框元素
const popupRef = ref<HTMLDivElement>()
// 元素定位
const insetTop = ref<string>("auto")
const insetRight = ref<string>("auto")
const insetBottom = ref<string>("auto")
const insetLeft = ref<string>("auto")
// 三角定位
const triangleTop = ref<string>("auto")
const triangleRight = ref<string>("auto")
const triangleBottom = ref<string>("auto")
const triangleLeft = ref<string>("auto")
const rotate = ref<string>("")

onMounted(() => {
    window.onresize = () => {
        return (() => {
            setInset(false)
        })();
    };
    window.onscroll = () => {
        setInset(false)
    };
})

// z-index
const zIndex = inject("pe-z-index", ref<number>(2000))

watch(show, newShow => {
    if (newShow) {
        zIndex.value++
        nextTick(() => {
            setInset(true)
        })
    }
})

const domRef = ref<HTMLElement>()

// 获取定位
const setInset = (flag: boolean) => {
    if (show.value || flag) {
        const insetObj = getInset(domRef, popupRef, props.domFlag)
        insetTop.value = insetObj.insetTop
        insetRight.value = insetObj.insetRight
        insetBottom.value = insetObj.insetBottom
        insetLeft.value = insetObj.insetLeft
        triangleTop.value = insetObj.triangleTop
        triangleRight.value = insetObj.triangleRight
        triangleBottom.value = insetObj.triangleBottom
        triangleLeft.value = insetObj.triangleLeft
        rotate.value = insetObj.rotate
    }
}

// 点击元素外部
const clickOutside = () => {
    if (show.value) {
        show.value = false
    }
}

defineExpose({
    setRef(value: any) {
        domRef.value = value
        nextTick(() => {
            setInset(true)
        })
    }
})
</script>
